package com.ciaojian.client.service;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ciaojian.core.constant.RedisConstant;
import com.ciaojian.core.enums.business.*;
import com.ciaojian.core.exception.EntityNotFoundException;
import com.ciaojian.core.mapper.*;
import com.ciaojian.core.model.*;
import com.ciaojian.core.model.Order;
import com.ciaojian.core.model.vo.CouponVo;
import com.ciaojian.core.service.CouponCodeService;
import com.ciaojian.core.util.LogUtil;
import com.ciaojian.core.util.RedisUtil;
import com.ciaojian.core.util.Result;
import com.ciaojian.miniapp.api.WxMiniAppApi;
import com.ciaojian.miniapp.model.request.submessage.BaseTemplate;
import com.ciaojian.miniapp.model.request.submessage.TakeCouponMessage;
import com.ciaojian.miniapp.model.request.submessage.TakeNumMessage;
import com.ciaojian.miniapp.model.request.submessage.TemplateIdEnum;
import com.ciaojian.miniapp.model.response.SubMessageSendResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;


/**
 * @author Atlakyn
 */
@Service
@Slf4j
public class CouponCodeServiceImpl extends CouponCodeService<CouponCodeMapper, CouponCode> implements IService<CouponCode> {
    @Resource
    private CouponServiceImpl couponService;
    @Resource
    private OrderServiceImpl orderService;
    @Resource
    private ActivityPopServiceImpl activityPopService;
    @Resource
    private StoreServiceImpl storeService;
    @Resource
    private ProductGroupServiceImpl productGroupService;
    @Resource
    private WorkerServiceImpl workerService;
    @Resource
    private CouponMapper couponMapper;
    @Resource
    private CouponCodeMapper couponCodeMapper;
    @Resource
    private OrderMapper orderMapper;
    @Resource
    private UserMapper userMapper;


    /**
     * 使用抖音的优惠券
     * couponId = 469,498,497
     *
     * @param couponVo 券类型
     * @param userId   订单ID
     */
    public void usedDouyinCouponCode(CouponVo couponVo, Integer userId) {
        // 抖音的优惠券
        List<Integer> douyinCoupons = Arrays.asList(469, 498, 497);
        // 如果使用了抖音的优惠券, 则记录进Redis
        if (douyinCoupons.contains(couponVo.getId())) {
            // key = USED_DOUYIN_ORDER:USER_ID
            RedisUtil.setKeyTimeAt(RedisConstant.USED_DOUYIN_ORDER + userId, "1", DateUtil.endOfDay(new Date()));
        }
    }


    /**
     * 抖音核销
     *
     * @param userId       /
     * @param workerId     /
     * @param storeId      /
     * @param productGroup /
     * @param douyinCode   /
     */
    public void douyinWriteOff(Integer userId,
                               Integer workerId,
                               Integer storeId,
                               ProductGroup productGroup,
                               String douyinCode,
                               String code,
                               Integer codeId) {
        // 生成订单
        Order order = new Order();
        order.setProductGroupId(productGroup.getId());
        order.setUserId(userId);
        order.setWorkerId(workerId);
        order.setWorkerName(workerService.getWorkerNameById(workerId));
        order.setInviterId(workerId);
        order.setStoreId(storeId);
        order.setStoreName(storeService.getTitleById(storeId));
        order.setType(productGroup.getName());
        order.setPayType(PayTypeEnum.DOUYIN_AUDIT.getDescription());
        order.setPayTime(new Date());
        order.setCouponCode(code);
        order.setCouponId(codeId);
        order.setPayTotal(BigDecimal.ZERO);
        // 价格
        order.setGoodsTotal(BigDecimal.valueOf(18L));
        order.setOrderNo(orderService.genOrderNo(OrderNoTypeEnum.PRODUCT_GROUP));
        order.setStatus(OrderStatusEnum.complete);
        order.setOrderType(OrderOrderTypeEnum.DOUYIN_WRITE_OFF);
        order.setYouzanCode(douyinCode);
        order.insert();

        // 根据产品组分解产品
        productGroupService.getById(order.getProductGroupId()).map(ProductGroup::getProductGroupDetailList).ifPresent(
                productGroupDetailList -> productGroupDetailList.forEach(productGroupDetail -> {
                    // 0会员卡 1次卡 2权益 3卡包
                    switch (productGroupDetail.getType()) {
                        case 0:
                            productGroupService.memberHandle(order, productGroupDetail.getProductId());
                            break;
                        case 1:
                            productGroupService.timesCardHandle(order, productGroupDetail.getProductId());
                            break;
                        case 2:
                            productGroupService.memberDetailHandle(order, productGroupDetail.getProductId(), CouponCodeOriginEnum.DOUYIN_WRITE_OFF);
                            break;
                        case 3:
                            productGroupService.couponPackageHandle(order, productGroupDetail.getProductId());
                            break;
                        default:
                            break;
                    }
                })
        );

//        // 给用户发放优惠券
//        memberDetailService.distributeCode(userId, Optional.of(memberDetail), order, CouponCodeOriginEnum.DOUYIN_WRITE_OFF);
    }

    /**
     * 获取用户权益详情
     *
     * @param orderId 订单ID
     * @return /
     */
    public Map<String, Object> getMemberDetailUserOwn(Integer orderId) {
        // 外部码
        String outsideCode = this.baseMapper.getOutsideCodeByOrderId(orderId);
        List<Map<String, Object>> couponCode = this.baseMapper.getCouponCodeBelongOrder(orderId);
        OrderReceiptAddress orderReceiptAddress = new OrderReceiptAddress().selectById(orderId);
        Map<String, Object> map = new HashMap<>(3);
        map.put("outsideCode", outsideCode);
        map.put("couponCode", couponCode);
        map.put("orderReceiptAddress", orderReceiptAddress);

        return map;
    }

    /**
     * 广告领券
     *
     * @param userId     领券用户
     * @param couponId   券类型id
     * @param activityId 广告id
     */
    public void advTakeCode(Integer userId, Integer couponId, Integer activityId, CouponCodeTakeRecordTypeEnum type) {
        Assert.isTrue(takeCodeLimit(userId, couponId), "您不可领取当前券");
        //裂变活动的邀请人可重复领券
        if (!type.equals(CouponCodeTakeRecordTypeEnum.MARKETING_SHARE_IN)) {
            // 判断同一张券用户是否领取过
            Assert.isTrue(this.checkNotTook(userId, couponId, activityId), "您已经领取");
        }

        // 给用户新增券
        QueryWrapper<CouponCode> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("coupon_id", couponId)
                .eq("status", 0)
                .isNull("user_id")
                .last("limit 1");
        CouponCode couponCode = new CouponCode().selectOne(queryWrapper);
        Assert.notNull(couponCode, "券码已被抢完");
        // 新增领取记录
        CouponCodeTakeRecord couponCodeTakeRecord = new CouponCodeTakeRecord();
        ShareRecord shareRecord = new ShareRecord();
        switch (type) {
            case POP_ACTIVITY:
                ActivityPop activityPop = activityPopService.getEffectPop(activityId);
                Assert.notNull(activityPop, "活动已结束");
                // 校验领取的券码是否为活动券码
                Assert.isTrue(activityPop.getCouponId().compareTo(couponId) == 0, "领取异常");
                break;
            case MARKET_SCAN:
                break;
            case MARKETING_SHARE:
                break;
            default:
                break;
        }

        couponCode.setStatus(1);
        couponCode.setUserId(userId);
        couponCode.setOrigin(CouponCodeOriginEnum.pop_collect);
        couponCode.setExpiredTime(couponService.getCouponExpiredTime(couponId));
        couponCode.updateById();

        couponCodeTakeRecord.setUserId(userId);
        couponCodeTakeRecord.setCouponId(couponId);
        couponCodeTakeRecord.setCouponCode(couponCode.getCode());
        couponCodeTakeRecord.setActivityId(activityId);
        couponCodeTakeRecord.setType(type);
        couponCodeTakeRecord.insert();
        // 领取数量 + 1
        couponService.addGetNum(couponId);
    }

    /**
     * 领券限制
     *
     * @param userId   用户
     * @param couponId 券码ID
     * @return 可领返回TRUE
     */
    private Boolean takeCodeLimit(Integer userId, Integer couponId) {
        // 硬编码443限无消费用户领取
        if (couponId.compareTo(443) == 0) {
            Integer numberOfComplete = orderService.countNumberOfCompleteByUserId(userId);
            return numberOfComplete.compareTo(0) <= 0;
        }
        return true;
    }

    /**
     * 领券
     *
     * @param userId   用户ID
     * @param couponId 券码ID
     */
    public CouponCode takeCode(Integer userId, Integer couponId) {
        Coupon coupon = Optional.ofNullable(couponService.getById(couponId))
                .orElseThrow(() -> new EntityNotFoundException(Coupon.class, "id", couponId));
        Date endDate = null;
        switch (coupon.getDateType()) {
            case 0:
                endDate = coupon.getEndTime();
                break;
            case 1:
                endDate = DateUtil.offset(new Date(), DateField.DAY_OF_YEAR, coupon.getSameDay());
                break;
            default:
                throw new RuntimeException("有效期类型错误,错误的值:" + coupon.getDateType());
        }
        return baseMapper.giveStock(userId, couponId, endDate);
    }


    public Page<Map<String, Object>> couponHistory(Page<Map<String, Object>> page, Integer userId) {
        return baseMapper.pageCouponHistory(page, userId);
    }

    /**
     * 赠送卡券
     *
     * @param granter    赠送方
     * @param couponCode 卡券券码
     * @return 赠送结果
     */
    @Transactional(rollbackFor = Exception.class)
    public CouponGrantRecord grantCode(User granter, CouponCode couponCode) {
        CouponGrantRecord record = new CouponGrantRecord()
                .setSource(granter.getId())
                .setCode(couponCode.getCode());
        record.insert();
        return record;
    }

    /**
     * 领取卡券
     *
     * @param targetId   被赠送方
     * @param couponCode 卡券券码
     * @param record     赠送记录
     * @return 赠送结果
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean receiveCode(Integer targetId, CouponCode couponCode, CouponGrantRecord record) {
        couponCode.setUserId(targetId);
        couponCode.updateById();
        record.setTarget(targetId);
//        record.setReceivedTime(new Date());
        return record.updateById();
    }


    @Override
    public Boolean checkNotTook(Integer userId, Integer couponId, Integer activityId) {
        // 判断用户是否领取过券
        QueryWrapper<CouponCodeTakeRecord> queryWrapper = new QueryWrapper<CouponCodeTakeRecord>()
                .eq("user_id", userId)
                .eq("activity_id", activityId)
                .eq("coupon_id", couponId)
                .last("limit 1");
        int count = new CouponCodeTakeRecord().selectCount(queryWrapper);
        LogUtil.writeBusinessLog("count = {}", count);
        return count == 0;
    }

    /**
     * 用户买券回调业务
     *
     * @param order 订单
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean buyCoupon(Order order) {
        // 给用户券
        Boolean b2 = this.baseMapper.updateByUserIdAndCouponId(order.getUserId(), order.getCouponId());
        if (b2) {
            // 修改订单状态
            order.setStatus(OrderStatusEnum.complete);
            order.setPayTotal(order.getGoodsTotal());
            order.setPayTime(new Date());
            return order.updateById();
        }
        return false;
    }


    /**
     * 用户买卡包回调业务
     *
     * @param order 订单
     */
    @Transactional(rollbackFor = Exception.class)
    public Boolean buyCouponPackage(Order order) {
        LogUtil.writePayLog("用户买卡包回调业务:订单信息:{}", order.toString());
        CouponPackage couponPackage = new CouponPackage().selectById(order.getCouponId());
        LogUtil.writePayLog("用户买卡包回调业务:卡包信息:{}", couponPackage.toString());
        String[] split = couponPackage.getCoupons().split(",");
        // 给用户券
        Boolean b2 = this.baseMapper.updateByUserIdAndCouponIds(order.getUserId(),order.getId(), split);
        if (b2) {
            // 修改订单状态
            order.setStatus(OrderStatusEnum.complete);
            order.setPayTotal(order.getGoodsTotal());
            order.setPayTime(new Date());
            return order.updateById();
        }
        return false;
    }

    /**
     * 给用户指定的卡券
     *
     * @param userId   用户
     * @param couponId 指定的卡券
     */
    public void giveCouponCode(Integer userId, Integer couponId) {

    }


    /**
     * 取消支付
     *
     * @param couponCodeId 券码
     * @return 取消结果
     */
    public Boolean cancelPay(Integer couponCodeId) {
        UpdateWrapper<CouponCode> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("user_id", null)
                .eq("id", couponCodeId);
        return this.update(updateWrapper);
    }

    /**
     * 取消支付
     *
     * @param couponCodeIds 券码集合
     * @return 取消结果
     */
    public Boolean cancelPay(List<Integer> couponCodeIds) {
        UpdateWrapper<CouponCode> updateWrapper = new UpdateWrapper<>();
        updateWrapper.set("user_id", null)
                .in("id", couponCodeIds);
        return this.update(updateWrapper);
    }

    public Map<String, Object> shoppingOrderInfo(Integer orderId){
        Map<String, Object> map = new HashMap<>(3);

        String outsideCode = this.baseMapper.getOutsideCodeByOrderId(orderId);
        List<Map<String, Object>> couponCode = this.baseMapper.getCouponCodeBelongOrder(orderId);
        OrderReceiptAddress orderReceiptAddress = new OrderReceiptAddress().selectById(orderId);

        map.put("couponCode", couponCode);
        map.put("orderReceiptAddress", orderReceiptAddress);
        map.put("outsideCode", outsideCode);
        return map;

    }


    public Result checkConsum(Integer userId,Integer couponId,String openId){
        try {
            if (userId !=82998) {
                QueryWrapper<CouponCodeTakeRecord> qw = new QueryWrapper<CouponCodeTakeRecord>()
                        .eq("user_id", userId)
                        .eq("activity_id", 55)
                        .eq("coupon_id", couponId)
                        .last("limit 1");
                int count = new CouponCodeTakeRecord().selectCount(qw);
                if (count > 0) {
                    return Result.error("已经领取过了");
                }
            }

            // 15  10  5
            QueryWrapper<CouponCode> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("coupon_id", couponId)
                    .eq("status", 0)
                    .isNull("user_id")
                    .last("limit 1");
            CouponCode couponCode = new CouponCode().selectOne(queryWrapper);
            Assert.notNull(couponCode, "券码已被抢完");

            couponCode.setStatus(1);
            couponCode.setUserId(userId);
            couponCode.setOrigin(CouponCodeOriginEnum.Hair_Check_Num);
            couponCode.setExpiredTime(couponService.getCouponExpiredTime(couponId));
            couponCode.setUpdateTime(new Date());
            couponCode.updateById();
            couponService.addGetNum(couponId);

            CouponCodeTakeRecord couponCodeTakeRecord = new CouponCodeTakeRecord();
            couponCodeTakeRecord.setUserId(userId);
            couponCodeTakeRecord.setCouponId(couponId);
            couponCodeTakeRecord.setCouponCode(couponCode.getCode());
            couponCodeTakeRecord.setActivityId(55);
            couponCodeTakeRecord.setType(CouponCodeTakeRecordTypeEnum.CHECK_HAIR_NUM);
            couponCodeTakeRecord.insert();

            Coupon coupon = couponMapper.selectById(couponId);

            return Result.ok(coupon);
        }catch (Exception e){
            log.info("hairAutoCodeERROR:"+userId+":"+e.getMessage());
            return Result.error("系统错误");
        }
    }


    public Result checkHairOrder(Integer userId){
        try {


            User user = userMapper.selectById(userId);

            String activityTime = "2022-09-28 00:00:00";
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date actiTime = simpleDateFormat.parse(activityTime);

            Date addTime = user.getAddTime();
            if (addTime.getTime() < actiTime.getTime()){
                return Result.error("老用户无法参加");
            }

            int isMember = orderMapper.checkMember(userId);
            if (isMember > 0) {
                return Result.error("已购买套餐");
            }


            int hairNum = orderMapper.checkHairOrderNum(userId);
            int couponId = 0;
            switch (hairNum) {
                case 1:
                    couponId = 531;  //15元券
                    break;
                case 2:
                    couponId = 532;  //10元券
                    break;
                case 3:
                    couponId = 533;  //5元券
                    break;
                default:
                   return Result.error("次数上限");
            }

            //第一次剪发15券  第二次10  第三次5
            QueryWrapper<CouponCode> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("coupon_id", couponId)
                    .eq("status", 0)
                    .isNull("user_id")
                    .last("limit 1");
            CouponCode couponCode = new CouponCode().selectOne(queryWrapper);
            Assert.notNull(couponCode, "券码已被抢完");


            Coupon coupon = couponMapper.selectById(couponId);

            QueryWrapper<CouponCodeTakeRecord> qw = new QueryWrapper<CouponCodeTakeRecord>()
                    .eq("user_id", userId)
                    .eq("activity_id", 55)
                    .eq("coupon_id", couponId)
                    .last("limit 1");
            int count = new CouponCodeTakeRecord().selectCount(qw);
            if (count > 0) {
                return Result.error("已经领取过了");
            }



            couponCode.setStatus(1);
            couponCode.setUserId(userId);
            couponCode.setOrigin(CouponCodeOriginEnum.Hair_Check_Num);
            couponCode.setExpiredTime(couponService.getCouponExpiredTime(couponId));
            couponCode.setUpdateTime(new Date());
            couponCode.updateById();
            couponService.addGetNum(couponId);

            CouponCodeTakeRecord couponCodeTakeRecord = new CouponCodeTakeRecord();
            couponCodeTakeRecord.setUserId(userId);
            couponCodeTakeRecord.setCouponId(couponId);
            couponCodeTakeRecord.setCouponCode(couponCode.getCode());
            couponCodeTakeRecord.setActivityId(55);
            couponCodeTakeRecord.setType(CouponCodeTakeRecordTypeEnum.CHECK_HAIR_NUM);
            couponCodeTakeRecord.insert();


            return Result.ok(coupon);

        }catch (Exception e){
            log.info("hairAutoCodeERROR:"+userId+":"+e.getMessage());
            return Result.error("系统错误");
        }
    }
}
